home *** CD-ROM | disk | FTP | other *** search
- {*********************************************************}
- {* AAGraphs *}
- {* Copyright (c) Julian M Bucknall 1998 *}
- {* All rights reserved. *}
- {*********************************************************}
- {* Graph classes *}
- {*********************************************************}
-
- {Note: this unit is released as freeware. In other words, you are free
- to use this unit in your own applications, however I retain all
- copyright to the code. JMB}
-
- unit AAGraphs;
-
- interface
-
- uses
- SysUtils, Classes, AAPQueue;
-
- const
- EdgeNotPresent = longint(-1);
-
- type
- TaaGraph = class
- private
- gIsDigraph : boolean;
- gNodeCount : integer;
- protected
- function gGetEdge(aFromIndex, aToIndex : integer) : longint; virtual; abstract;
- function gGetNode(aIndex : integer) : pointer; virtual; abstract;
- procedure gSetEdge(aFromIndex, aToIndex : integer;
- aValue : longint); virtual; abstract;
- procedure gSetNode(aIndex : integer; aValue : pointer); virtual; abstract;
- public
- constructor Create(aNodeCount : integer);
-
- function GetNodeEdge(aFromIndex : integer;
- aNthEdge : integer;
- var aEdge : longint;
- var aToIndex : integer) : boolean; virtual; abstract;
-
- property Edges[aFromIndex, aToIndex : integer] : longint
- read gGetEdge write gSetEdge;
-
- property IsDigraph : boolean
- read gIsDigraph;
-
- property NodeCount : integer
- read gNodeCount;
-
- property Nodes[aIndex : integer] : pointer
- read gGetNode write gSetNode;
- end;
-
- TaaFullMatrixGraph = class(TaaGraph)
- private
- mgNodes : TList;
- mgEdges : TList;
- protected
- function gGetEdge(aFromIndex, aToIndex : integer) : longint; override;
- function gGetNode(aIndex : integer) : pointer; override;
- procedure gSetEdge(aFromIndex, aToIndex : integer;
- aValue : longint); override;
- procedure gSetNode(aIndex : integer; aValue : pointer); override;
-
- public
- constructor Create(aNodeCount : integer; aIsDigraph : boolean);
- destructor Destroy; override;
-
- function GetNodeEdge(aFromIndex : integer;
- aNthEdge : integer;
- var aEdge : longint;
- var aToIndex : integer) : boolean; override;
- end;
-
- TaaTriMatrixGraph = class(TaaGraph)
- private
- mgNodes : TList;
- mgEdges : TList;
- protected
- function gGetEdge(aFromIndex, aToIndex : integer) : longint; override;
- function gGetNode(aIndex : integer) : pointer; override;
- procedure gSetEdge(aFromIndex, aToIndex : integer;
- aValue : longint); override;
- procedure gSetNode(aIndex : integer; aValue : pointer); override;
-
- public
- constructor Create(aNodeCount : integer);
- destructor Destroy; override;
-
- function GetNodeEdge(aFromIndex : integer;
- aNthEdge : integer;
- var aEdge : longint;
- var aToIndex : integer) : boolean; override;
- end;
-
- TaaLinkListGraph = class(TaaGraph)
- private
- lgNodes : TList;
- protected
- function gGetEdge(aFromIndex, aToIndex : integer) : longint; override;
- function gGetNode(aIndex : integer) : pointer; override;
- procedure gSetEdge(aFromIndex, aToIndex : integer;
- aValue : longint); override;
- procedure gSetNode(aIndex : integer; aValue : pointer); override;
-
- procedure lgCreateEmptyLinkedList(aAtIndex : integer);
- procedure lgDestroyLinkedList(aAtIndex : integer);
- procedure lgSetEdgePrim(aFromIndex, aToIndex : integer;
- aValue : longint);
- public
- constructor Create(aNodeCount : integer; aIsDigraph : boolean);
- destructor Destroy; override;
-
- function GetNodeEdge(aFromIndex : integer;
- aNthEdge : integer;
- var aEdge : longint;
- var aToIndex : integer) : boolean; override;
- end;
-
- type
- TaaProcessNode = procedure (aSender : TObject;
- aNodeInx : integer;
- aExtraData : pointer);
- TaaEvalPriority = function (aSender : TObject;
- aFromIndex : integer;
- aEdgeCost : longint;
- aToIndex : integer) : longint;
-
- TaaDepthFirstIterator = class
- private
- dfiGraph : TaaGraph;
- dfiNodes : TList;
- dfiPostProcess : TaaProcessNode;
- dfiPreProcess : TaaProcessNode;
- dfiProcessSortedNode : TaaProcessNode;
- protected
- procedure dfiDestroyCounter(aIndex : integer);
- procedure dfiExecutePrim(aFromIndex : integer;
- var aHasCycle : boolean;
- aExtraData : pointer);
- public
- constructor Create(aGraph : TaaGraph);
- destructor Destroy; override;
-
- procedure Execute(aFromIndex : integer;
- var aHasCycle : boolean;
- aExtraData : pointer);
- procedure ExecuteAll(var aHasCycle : boolean;
- aExtraData : pointer);
- procedure Reset;
- procedure TopologicalSort(aExtraData : pointer);
-
- property OnPreProcess : TaaProcessNode
- read dfiPreProcess write dfiPreProcess;
- property OnPostProcess : TaaProcessNode
- read dfiPostProcess write dfiPostProcess;
- property OnProcessSortedNode : TaaProcessNode
- read dfiProcessSortedNode write dfiProcessSortedNode;
- end;
-
- TaaBreadthFirstIterator = class
- private
- bfiGraph : TaaGraph;
- bfiNodes : TList;
- bfiPostProcess : TaaProcessNode;
- bfiPreProcess : TaaProcessNode;
- bfiPrintNode : TaaProcessNode;
- bfiQueue : pointer;
- bfiQueueTail : pointer;
- protected
- procedure bfiDestroyCounter(aIndex : integer);
-
- // internal queue
- procedure bfiClearQueue;
- function bfiDequeue : integer;
- procedure bfiEnqueue(aIndex : integer);
- function bfiQueueIsEmpty : boolean;
-
- function bfiShortPathPrim(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
- public
- constructor Create(aGraph : TaaGraph);
- destructor Destroy; override;
-
- procedure Execute(aFromIndex : integer; aExtraData : pointer);
- procedure ExecuteAll(aExtraData : pointer);
- procedure Reset;
- function ShortestPath(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
-
- property OnPreProcess : TaaProcessNode
- read bfiPreProcess write bfiPreProcess;
- property OnPostProcess : TaaProcessNode
- read bfiPostProcess write bfiPostProcess;
- property OnPrintNode : TaaProcessNode
- read bfiPrintNode write bfiPrintNode;
- end;
-
- TaaPriorityFirstIterator = class
- private
- pfiGraph : TaaGraph;
- pfiNodes : TList;
- pfiPostProcess : TaaProcessNode;
- pfiPreProcess : TaaProcessNode;
- pfiPrintNode : TaaProcessNode;
- pfiQueue : TaaPriorityQueueEx;
- protected
- procedure pfiDestroyCounter(aIndex : integer);
-
- function pfiTracePathPrim(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
- public
- constructor Create(aGraph : TaaGraph);
- destructor Destroy; override;
-
- function GetPriority(aNodeIndex : integer) : longint;
- procedure Execute(aEvalPriority : TaaEvalPriority;
- aFromIndex : integer;
- aExtraData : pointer);
- procedure ExecuteAll(aEvalPriority : TaaEvalPriority;
- aExtraData : pointer);
- procedure Reset;
- function TracePath(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
-
- property OnPreProcess : TaaProcessNode
- read pfiPreProcess write pfiPreProcess;
- property OnPostProcess : TaaProcessNode
- read pfiPostProcess write pfiPostProcess;
- property OnPrintNode : TaaProcessNode
- read pfiPrintNode write pfiPrintNode;
- end;
-
- function EvalPrimsPriority(aSender : TObject;
- aFromIndex : integer;
- aEdgeCost : longint;
- aToIndex : integer) : longint;
-
- function EvalDijkstrasPriority(aSender : TObject;
- aFromIndex : integer;
- aEdgeCost : longint;
- aToIndex : integer) : longint;
-
- procedure MinSpanningTree(aGraph : TaaGraph;
- aProcessNode : TaaProcessNode;
- aExtraData : pointer);
-
- procedure SmallestCostPath(aGraph : TaaGraph;
- aFromIndex : integer;
- aToIndex : integer;
- aProcessNode : TaaProcessNode;
- aExtraData : pointer);
-
- implementation
-
- const
- InfinitePriority = MaxLongint;
-
-
- {===TaaGraph=========================================================}
- constructor TaaGraph.Create(aNodeCount : integer);
- begin
- inherited Create;
- gNodeCount := aNodeCount;
- end;
- {====================================================================}
-
-
- {===TaaFullMatrixGraph===============================================}
- constructor TaaFullMatrixGraph.Create(aNodeCount : integer; aIsDigraph : boolean);
- var
- i : integer;
- begin
- inherited Create(aNodeCount);
- mgNodes := TList.Create;
- mgNodes.Count := aNodeCount;
- mgEdges := TList.Create;
- mgEdges.Count := aNodeCount * aNodeCount;
- for i := 0 to pred(mgEdges.Count) do
- mgEdges[i] := pointer(EdgeNotPresent);
- gIsDigraph := aIsDigraph;
- end;
- {--------}
- destructor TaaFullMatrixGraph.Destroy;
- begin
- mgEdges.Free;
- mgNodes.Free;
- inherited Destroy;
- end;
- {--------}
- function TaaFullMatrixGraph.GetNodeEdge(aFromIndex : integer;
- aNthEdge : integer;
- var aEdge : longint;
- var aToIndex : integer) : boolean;
- var
- i : integer;
- BeginIndex : integer;
- begin
- Result := false;
- if (aFromIndex < 0) or
- (aFromIndex >= mgNodes.Count) or
- (aNthEdge < 0) then
- Exit;
- BeginIndex := aFromIndex * NodeCount;
- for i := BeginIndex to pred(BeginIndex + NodeCount) do begin
- if (mgEdges[i] <> nil) then begin
- if (aNthEdge = 0) then begin
- Result := true;
- aEdge := longint(mgEdges[i]);
- aToIndex := i - BeginIndex;
- Exit;
- end;
- dec(aNthEdge);
- end;
- end;
- end;
- {--------}
- function TaaFullMatrixGraph.gGetEdge(aFromIndex, aToIndex : integer) : longint;
- begin
- if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gGetEdge: from node index out of range');
- if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gGetEdge: to node index out of range');
- Result := longint(mgEdges[(aFromIndex * NodeCount) + aToIndex]);
- end;
- {--------}
- function TaaFullMatrixGraph.gGetNode(aIndex : integer) : pointer;
- begin
- if (aIndex < 0) or (aIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gGetNode: node index out of range');
- Result := mgNodes[aIndex];
- end;
- {--------}
- procedure TaaFullMatrixGraph.gSetEdge(aFromIndex, aToIndex : integer;
- aValue : longint);
- begin
- if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gSetEdge: from node index out of range');
- if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gSetEdge: to node index out of range');
- mgEdges[(aFromIndex * NodeCount) + aToIndex] := pointer(aValue);
- if (not IsDigraph) and (aFromIndex <> aToIndex) then
- mgEdges[(aToIndex * NodeCount) + aFromIndex] := pointer(aValue);
- end;
- {--------}
- procedure TaaFullMatrixGraph.gSetNode(aIndex : integer; aValue : pointer);
- begin
- if (aIndex < 0) or (aIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gSetNode: node index out of range');
- mgNodes[aIndex] := aValue;
- end;
- {====================================================================}
-
-
- {===TaaTriMatrixGraph================================================}
- constructor TaaTriMatrixGraph.Create(aNodeCount : integer);
- var
- i : integer;
- begin
- inherited Create(aNodeCount);
- mgNodes := TList.Create;
- mgNodes.Count := aNodeCount;
- mgEdges := TList.Create;
- mgEdges.Count := (aNodeCount * succ(aNodeCount)) div 2;
- for i := 0 to pred(mgEdges.Count) do
- mgEdges[i] := pointer(EdgeNotPresent);
- end;
- {--------}
- destructor TaaTriMatrixGraph.Destroy;
- begin
- mgEdges.Free;
- mgNodes.Free;
- inherited Destroy;
- end;
- {--------}
- function TaaTriMatrixGraph.GetNodeEdge(aFromIndex : integer;
- aNthEdge : integer;
- var aEdge : longint;
- var aToIndex : integer) : boolean;
- var
- ArrayInx : integer;
- ToIndex : integer;
- begin
- Result := false;
- if (aFromIndex < 0) or
- (aFromIndex >= mgNodes.Count) or
- (aNthEdge < 0) then
- Exit;
- ArrayInx := (aFromIndex * succ(aFromIndex)) div 2;
- ToIndex := 0;
- {first go along horizontally along a row}
- while (ToIndex <= aFromIndex) do begin
- if (mgEdges[ArrayInx] <> nil) then begin
- if (aNthEdge = 0) then begin
- Result := true;
- aEdge := longint(mgEdges[ArrayInx]);
- aToIndex := ToIndex;
- Exit;
- end;
- dec(aNthEdge);
- end;
- inc(ToIndex);
- inc(ArrayInx);
- end;
- {then go vertically down a column}
- inc(ArrayInx, pred(ToIndex));
- while (ToIndex < NodeCount) do begin
- if (mgEdges[ArrayInx] <> nil) then begin
- if (aNthEdge = 0) then begin
- Result := true;
- aEdge := longint(mgEdges[ArrayInx]);
- aToIndex := ToIndex;
- Exit;
- end;
- dec(aNthEdge);
- end;
- inc(ToIndex);
- inc(ArrayInx, ToIndex);
- end;
- end;
- {--------}
- function TaaTriMatrixGraph.gGetEdge(aFromIndex, aToIndex : integer) : longint;
- var
- Temp : integer;
- begin
- if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gGetEdge: from node index out of range');
- if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gGetEdge: to node index out of range');
- if (aFromIndex < aToIndex) then begin
- Temp := aFromIndex;
- aFromIndex := aToIndex;
- aToIndex := Temp;
- end;
- Result := longint(mgEdges[(aFromIndex * succ(aFromIndex)) div 2 + aToIndex]);
- end;
- {--------}
- function TaaTriMatrixGraph.gGetNode(aIndex : integer) : pointer;
- begin
- if (aIndex < 0) or (aIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gGetNode: node index out of range');
- Result := mgNodes[aIndex];
- end;
- {--------}
- procedure TaaTriMatrixGraph.gSetEdge(aFromIndex, aToIndex : integer;
- aValue : longint);
- var
- Temp : integer;
- begin
- if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gSetEdge: from node index out of range');
- if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gSetEdge: to node index out of range');
- if (aFromIndex < aToIndex) then begin
- Temp := aFromIndex;
- aFromIndex := aToIndex;
- aToIndex := Temp;
- end;
- mgEdges[(aFromIndex * succ(aFromIndex)) div 2 + aToIndex] := pointer(aValue);
- end;
- {--------}
- procedure TaaTriMatrixGraph.gSetNode(aIndex : integer; aValue : pointer);
- begin
- if (aIndex < 0) or (aIndex >= mgNodes.Count) then
- raise Exception.Create('TaaTriMatrixGraph.gSetNode: node index out of range');
- mgNodes[aIndex] := aValue;
- end;
- {====================================================================}
-
-
- {====================================================================}
- type
- PllNode = ^TllNode;
- TllNode = packed record
- llnNext : PllNode; // next node
- llnNodeInx : integer; // node index
- case boolean {read as: is this the first node?} of
- false : (llnEdge : longint); // edge value or cost
- true : (llnNode : pointer); // node value
- end;
- {-------}
- constructor TaaLinkListGraph.Create(aNodeCount : integer; aIsDigraph : boolean);
- var
- i : integer;
- begin
- inherited Create(aNodeCount);
- lgNodes := TList.Create;
- lgNodes.Count := aNodeCount;
- for i := 0 to pred(aNodeCount) do
- lgCreateEmptyLinkedList(i);
- gIsDigraph := aIsDigraph;
- end;
- {--------}
- destructor TaaLinkListGraph.Destroy;
- var
- i : integer;
- begin
- for i := 0 to pred(NodeCount) do
- lgDestroyLinkedList(i);
- lgNodes.Free;
- inherited Destroy;
- end;
- {--------}
- function TaaLinkListGraph.GetNodeEdge(aFromIndex : integer;
- aNthEdge : integer;
- var aEdge : longint;
- var aToIndex : integer) : boolean;
- var
- WalkNode : PllNode;
- begin
- Result := false;
- if (aFromIndex < 0) or
- (aFromIndex >= lgNodes.Count) or
- (aNthEdge < 0) then
- Exit;
- WalkNode := lgNodes[aFromIndex];
- while (WalkNode <> nil) and (aNthEdge >= 0) do begin
- WalkNode := WalkNode^.llnNext;
- dec(aNthEdge);
- end;
- if (WalkNode = nil) or (WalkNode^.llnNext = nil) then
- Exit;
- Result := true;
- aEdge := WalkNode^.llnEdge;
- aToIndex := WalkNode^.llnNodeInx;
- end;
- {--------}
- function TaaLinkListGraph.gGetEdge(aFromIndex, aToIndex : integer) : longint;
- var
- WalkNode : PllNode;
- begin
- if (aFromIndex < 0) or (aFromIndex >= lgNodes.Count) then
- raise Exception.Create('TaaLinkListGraph.gSetEdge: from node index out of range');
- if (aToIndex < 0) or (aToIndex >= lgNodes.Count) then
- raise Exception.Create('TaaLinkListGraph.gSetEdge: to node index out of range');
- Result := EdgeNotPresent;
- WalkNode := lgNodes[aFromIndex];
- while (WalkNode^.llnNodeInx < aToIndex) do
- WalkNode := WalkNode^.llnNext;
- if (WalkNode^.llnNodeInx = aToIndex) then
- Result := WalkNode^.llnEdge;
- end;
- {--------}
- function TaaLinkListGraph.gGetNode(aIndex : integer) : pointer;
- begin
- if (aIndex < 0) or (aIndex >= lgNodes.Count) then
- raise Exception.Create('TaaLinkListGraph.gGetNode: node index out of range');
- Result := PllNode(lgNodes[aIndex])^.llnNode;
- end;
- {--------}
- procedure TaaLinkListGraph.gSetEdge(aFromIndex, aToIndex : integer;
- aValue : longint);
- begin
- if (aFromIndex < 0) or (aFromIndex >= lgNodes.Count) then
- raise Exception.Create('TaaLinkListGraph.gSetEdge: from node index out of range');
- if (aToIndex < 0) or (aToIndex >= lgNodes.Count) then
- raise Exception.Create('TaaLinkListGraph.gSetEdge: to node index out of range');
- lgSetEdgePrim(aFromIndex, aToIndex, aValue);
- if (not IsDigraph) and (aFromIndex <> aToIndex) then
- lgSetEdgePrim(aToIndex, aFromIndex, aValue);
- end;
- {--------}
- procedure TaaLinkListGraph.gSetNode(aIndex : integer; aValue : pointer);
- begin
- if (aIndex < 0) or (aIndex >= lgNodes.Count) then
- raise Exception.Create('TaaLinkListGraph.gSetNode: node index out of range');
- PllNode(lgNodes[aIndex])^.llnNode := aValue;
- end;
- {--------}
- procedure TaaLinkListGraph.lgCreateEmptyLinkedList(aAtIndex : integer);
- var
- FirstNode : PllNode;
- LastNode : PllNode;
- begin
- New(LastNode);
- with LastNode^ do begin
- llnNext := nil;
- llnEdge := 0;
- llnNodeInx := $7FFFFFFF; // greater than any node index
- end;
- New(FirstNode);
- with FirstNode^ do begin
- llnNext := LastNode;
- llnNode := nil;
- llnNodeInx := -1; // less than any node index
- end;
- lgNodes[aAtIndex] := FirstNode;
- end;
- {--------}
- procedure TaaLinkListGraph.lgDestroyLinkedList(aAtIndex : integer);
- var
- Dad, Son : PllNode;
- begin
- Son := lgNodes[aAtIndex];
- while (Son <> nil) do begin
- Dad := Son;
- Son := Dad^.llnNext;
- Dispose(Dad);
- end;
- end;
- {--------}
- procedure TaaLinkListGraph.lgSetEdgePrim(aFromIndex, aToIndex : integer;
- aValue : longint);
- var
- DadNode, WalkNode, NewNode : PllNode;
- begin
- DadNode := nil;
- WalkNode := lgNodes[aFromIndex];
- while (WalkNode^.llnNodeInx < aToIndex) do begin
- DadNode := WalkNode;
- WalkNode := DadNode^.llnNext;
- end;
- if (WalkNode^.llnNodeInx = aToIndex) then
- WalkNode^.llnEdge := aValue
- else begin
- New(NewNode);
- with NewNode^ do begin
- llnNext := WalkNode;
- llnEdge := aValue;
- llnNodeInx := aToIndex;
- end;
- DadNode^.llnNext := NewNode;
- end;
- end;
- {====================================================================}
-
-
- type
- PitrCounter = ^TitrCounter;
- TitrCounter = packed record {Counter record for iterators}
- cIndex : integer; {..index of this item in list}
- cMarker : integer; {..0-unseen; 1-preproc'd; 2-postproc'd}
- cParent : integer; {..index of predecessor node}
- cLevel : integer; {..distance from source node}
- cPriority : longint; {..priority of node}
- cHandle : TaaPQHandle; {..handle of node in priority queue}
- end;
-
- type
- PbfiListItem = ^TbfiListItem;
- TbfiListItem = record {Linked list item for topo sort}
- liIndex : integer; {..node index}
- liNext : PbfiListItem; {..next linked list item}
- end;
-
- type
- PbfiQueueItem = ^TbfiQueueItem;
- TbfiQueueItem = record {Queue item for breadth-1st traversal}
- qiIndex : integer; {..node index}
- qiNext : PbfiQueueItem; {..next queue item}
- end;
-
-
-
- {===Helper routines for iterators====================================}
- procedure TsAddToList(aSender : TObject;
- aNodeInx : integer;
- aExtraData : pointer);
- var
- LinkedList : PbfiListItem absolute aExtraData;
- Item : PbfiListItem;
- begin
- New(Item);
- Item^.liIndex := aNodeInx;
- Item^.liNext := LinkedList^.liNext;
- LinkedList^.liNext := Item;
- end;
- {--------}
- function ComparePriority(const aItem1, aItem2 : pointer) : integer;
- begin
- // do the reverse of the usual comparison. ie compare aItem2
- // against aItem1: this will produce a min-heap priority queue
- Result := PitrCounter(aItem2).cPriority -
- PitrCounter(aItem1).cPriority;
- end;
- {====================================================================}
-
-
- {===TaaDepthFirstIterator============================================}
- constructor TaaDepthFirstIterator.Create(aGraph : TaaGraph);
- var
- i : integer;
- begin
- inherited Create;
- if (aGraph = nil) then
- raise Exception.Create('TaaDepthFirstIterator.Create: graph object is nil');
- dfiGraph := aGraph;
- dfiNodes := TList.Create;
- dfiNodes.Count := aGraph.NodeCount;
- for i := 0 to pred(dfiNodes.Count) do
- dfiNodes[i] := AllocMem(sizeof(TitrCounter));
- Reset;
- end;
- {--------}
- destructor TaaDepthFirstIterator.Destroy;
- var
- i : integer;
- begin
- for i := 0 to pred(dfiNodes.Count) do
- dfiDestroyCounter(i);
- dfiNodes.Free;
- inherited Destroy;
- end;
- {--------}
- procedure TaaDepthFirstIterator.dfiDestroyCounter(aIndex : integer);
- var
- Counter : PitrCounter;
- begin
- Counter := dfiNodes[aIndex];
- if (Counter <> nil) then
- Dispose(Counter);
- end;
- {--------}
- procedure TaaDepthFirstIterator.dfiExecutePrim(aFromIndex : integer;
- var aHasCycle : boolean;
- aExtraData : pointer);
- var
- i : integer;
- NewNodeInx : integer;
- Edge : longint;
- OurLevel : integer;
- begin
- // perform preprocessing on the node
- if Assigned(dfiPreProcess) then
- dfiPreProcess(Self, aFromIndex, aExtraData);
- // mark the node as preprocessed
- with PitrCounter(dfiNodes[aFromIndex])^ do begin
- cMarker := 1;
- OurLevel := cLevel;
- end;
- // iterate through the edges from this node
- i := 0;
- while dfiGraph.GetNodeEdge(aFromIndex, i, Edge, NewNodeInx) do begin
- with PitrCounter(dfiNodes[NewNodeInx])^ do begin
- if (cMarker = 0) then begin
- cParent := aFromIndex;
- cLevel := succ(OurLevel);
- dfiExecutePrim(NewNodeInx, aHasCycle, aExtraData);
- end
- else if (cMarker = 1) then begin
- // a cycle has been found!
- aHasCycle := true;
- end;
- end;
- inc(i);
- end;
- // perform postprocessing on the node
- if Assigned(dfiPostProcess) then
- dfiPostProcess(Self, aFromIndex, aExtraData);
- // mark the node as postprocessed
- with PitrCounter(dfiNodes[aFromIndex])^ do begin
- cMarker := 2;
- end;
- end;
- {--------}
- procedure TaaDepthFirstIterator.Execute(aFromIndex : integer;
- var aHasCycle : boolean;
- aExtraData : pointer);
- begin
- aHasCycle := false;
- dfiExecutePrim(aFromIndex, aHasCycle, aExtraData);
- end;
- {--------}
- procedure TaaDepthFirstIterator.ExecuteAll(var aHasCycle : boolean;
- aExtraData : pointer);
- var
- i : integer;
- ithHasCycle : boolean;
- begin
- aHasCycle := false;
- for i := 0 to pred(dfiGraph.NodeCount) do begin
- if (PitrCounter(dfiNodes[i])^.cMarker = 0) then begin
- Execute(i, ithHasCycle, aExtraData);
- aHasCycle := aHasCycle or ithHasCycle;
- end;
- end;
- end;
- {--------}
- procedure TaaDepthFirstIterator.Reset;
- var
- i : integer;
- begin
- for i := 0 to pred(dfiNodes.Count) do begin
- with PitrCounter(dfiNodes[i])^ do begin
- cIndex := i;
- cMarker := 0;
- cParent := -1;
- cLevel := 0;
- end;
- end;
- end;
- {--------}
- procedure TaaDepthFirstIterator.TopologicalSort(aExtraData : pointer);
- var
- SavedPreProc : TaaProcessNode;
- SavedPostProc : TaaProcessNode;
- TSList : PbfiListItem;
- Head, Temp : PbfiListItem;
- HasCycle : boolean;
- begin
- if not dfiGraph.IsDigraph then
- raise Exception.Create('TaaDepthFirstIterator.TopologicalSort: you can only sort a digraph');
- SavedPreProc := OnPreProcess;
- SavedPostProc := OnPostProcess;
- OnPreProcess := nil;
- OnPostProcess := TSAddToList;
- try
- // create the linked list
- New(TSList);
- TSList^.liNext := nil;
- try
- // now execute the depth first traversal on all the nodes: this
- // will add all the nodes to our linked list
- Reset;
- ExecuteAll(HasCycle, TSList);
- // now trigger the event handler, cleaning up the linked list as
- // we go
- Head := TSList^.liNext;
- try
- // if there was a cycle, the topo sort is meaningless
- if HasCycle then
- raise Exception.Create('TaaDepthFirstIterator.TopologicalSort: digraph is not acyclic');
- // walk the linked list
- while (Head <> nil) do begin
- // process the head node
- if Assigned(dfiProcessSortedNode) then
- dfiProcessSortedNode(Self, Head^.liIndex, aExtraData);
- // move down the list, dispose of the old head node
- Temp := Head;
- Head := Head^.liNext;
- Dispose(Temp);
- end;
- except
- // on error clean up the remainder of the linked list
- while (Head <> nil) do begin
- Temp := Head;
- Head := Head^.liNext;
- Dispose(Temp);
- end;
- raise;
- end;
- finally
- Dispose(TSList);
- end;
- finally
- OnPreProcess := SavedPreProc;
- OnPostProcess := SavedPostProc;
- end;
- end;
- {====================================================================}
-
-
- {===TaaBreadthFirstIterator============================================}
- constructor TaaBreadthFirstIterator.Create(aGraph : TaaGraph);
- var
- i : integer;
- begin
- inherited Create;
- if (aGraph = nil) then
- raise Exception.Create('TaaBreadthFirstIterator.Create: graph object is nil');
- bfiGraph := aGraph;
- bfiNodes := TList.Create;
- bfiNodes.Count := aGraph.NodeCount;
- for i := 0 to pred(bfiNodes.Count) do
- bfiNodes[i] := AllocMem(sizeof(TitrCounter));
- Reset;
- end;
- {--------}
- destructor TaaBreadthFirstIterator.Destroy;
- var
- i : integer;
- begin
- for i := 0 to pred(bfiNodes.Count) do
- bfiDestroyCounter(i);
- bfiNodes.Free;
- inherited Destroy;
- end;
- {--------}
- procedure TaaBreadthFirstIterator.bfiClearQueue;
- var
- Head, Temp : PbfiQueueItem;
- begin
- Head := PbfiQueueItem(bfiQueue);
- while (Head <> nil) do begin
- Temp := Head;
- Head := Head^.qiNext;
- Dispose(Temp);
- end;
- end;
- {--------}
- function TaaBreadthFirstIterator.bfiDequeue : integer;
- var
- Head : PbfiQueueItem;
- begin
- Head := PbfiQueueItem(bfiQueue);
- if (Head = nil) then
- Result := -1
- else begin
- bfiQueue := pointer(Head^.qiNext);
- Result := Head^.qiIndex;
- Dispose(Head);
- if (bfiQueue = nil) then
- bfiQueueTail := nil;
- end;
- end;
- {--------}
- procedure TaaBreadthFirstIterator.bfiDestroyCounter(aIndex : integer);
- var
- Counter : PitrCounter;
- begin
- Counter := bfiNodes[aIndex];
- if (Counter <> nil) then
- Dispose(Counter);
- end;
- {--------}
- procedure TaaBreadthFirstIterator.bfiEnqueue(aIndex : integer);
- var
- Temp : PbfiQueueItem;
- begin
- New(Temp);
- Temp^.qiIndex := aIndex;
- Temp^.qiNext := nil;
- if (bfiQueue = nil) then
- bfiQueue := pointer(Temp)
- else
- PbfiQueueItem(bfiQueueTail)^.qiNext := Temp;
- bfiQueueTail := pointer(Temp);
- end;
- {--------}
- function TaaBreadthFirstIterator.bfiQueueIsEmpty : boolean;
- begin
- Result := bfiQueue = nil;
- end;
- {--------}
- function TaaBreadthFirstIterator.bfiShortPathPrim(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
- var
- Parent : integer;
- begin
- if (aFromIndex = aToIndex) then begin
- {we reached the source node, so print it & return success}
- if Assigned(bfiPrintNode) then
- bfiPrintNode(Self, aToIndex, aExtraData);
- Result := true;
- end
- else begin
- Parent := PitrCounter(bfiNodes[aToIndex])^.cParent;
- if (Parent = -1) then begin
- {we've hit a dead end-there is no path back to the source node}
- Result := false;
- end
- else begin
- {recurse to the parent, if successful print this node}
- if bfiShortPathPrim(aFromIndex, Parent, aExtraData) then begin
- if Assigned(bfiPrintNode) then
- bfiPrintNode(Self, aToIndex, aExtraData);
- Result := true;
- end
- else
- Result := false;
- end;
- end;
- end;
- {--------}
- procedure TaaBreadthFirstIterator.Execute(aFromIndex : integer;
- aExtraData : pointer);
- var
- i : integer;
- NewNodeInx : integer;
- Edge : longint;
- OurLevel : integer;
- OurIndex : integer;
- begin
- // perform preprocessing on the node
- if Assigned(bfiPreProcess) then
- bfiPreProcess(Self, aFromIndex, aExtraData);
- // mark the node as preprocessed
- with PitrCounter(bfiNodes[aFromIndex])^ do begin
- cMarker := 1;
- end;
- // push the node onto the queue
- bfiEnqueue(aFromIndex);
- // whilst there are still items in the queue...
- while not bfiQueueIsEmpty do begin
- // pop the next item off the queue
- OurIndex := bfiDequeue;
- // perform postprocessing on the node
- if Assigned(bfiPostProcess) then
- bfiPostProcess(Self, OurIndex, aExtraData);
- // mark the node as postprocessed
- with PitrCounter(bfiNodes[OurIndex])^ do begin
- cMarker := 2;
- OurLevel := cLevel;
- end;
- // iterate through the edges from this node, push unvisited nodes
- // onto the queue
- i := 0;
- while bfiGraph.GetNodeEdge(OurIndex, i, Edge, NewNodeInx) do begin
- with PitrCounter(bfiNodes[NewNodeInx])^ do begin
- if (cMarker = 0) then begin
- // update process information
- cParent := OurIndex;
- cLevel := succ(OurLevel);
- // perform preprocessing on the node
- if Assigned(bfiPreProcess) then
- bfiPreProcess(Self, NewNodeInx, aExtraData);
- // mark the node as preprocessed
- cMarker := 1;
- // push the node onto the queue
- bfiEnqueue(NewNodeInx);
- end;
- end;
- inc(i);
- end;
- end;
- end;
- {--------}
- procedure TaaBreadthFirstIterator.ExecuteAll(aExtraData : pointer);
- var
- i : integer;
- begin
- for i := 0 to pred(bfiGraph.NodeCount) do begin
- if (PitrCounter(bfiNodes[i])^.cMarker = 0) then
- Execute(i, aExtraData);
- end;
- end;
- {--------}
- procedure TaaBreadthFirstIterator.Reset;
- var
- i : integer;
- begin
- for i := 0 to pred(bfiNodes.Count) do begin
- with PitrCounter(bfiNodes[i])^ do begin
- cIndex := i;
- cMarker := 0;
- cParent := -1;
- cLevel := 0;
- end;
- end;
- end;
- {--------}
- function TaaBreadthFirstIterator.ShortestPath(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
- var
- SavedPreProc : TaaProcessNode;
- SavedPostProc : TaaProcessNode;
- begin
- // we don't want any interruptions
- SavedPreProc := OnPreProcess;
- SavedPostProc := OnPostProcess;
- OnPreProcess := nil;
- OnPostProcess := nil;
- try
- // first execute the breadth first traversal: this sets up our
- // internal data structure
- Reset;
- Execute(aFromIndex, nil);
- // now traverse from the ToIndex node back to the FromIndex node
- // pushing visited nodes on the stack: we'll then unwind the stack
- // to print the shortest path
- Result := bfiShortPathPrim(aFromIndex, aToIndex, aExtraData);
- finally
- OnPreProcess := SavedPreProc;
- OnPostProcess := SavedPostProc;
- end;
- end;
- {====================================================================}
-
-
- {===TaaPriorityFirstIterator=========================================}
- constructor TaaPriorityFirstIterator.Create(aGraph : TaaGraph);
- var
- i : integer;
- begin
- inherited Create;
- if (aGraph = nil) then
- raise Exception.Create('TaaPriorityFirstIterator.Create: graph object is nil');
- pfiGraph := aGraph;
- pfiNodes := TList.Create;
- pfiNodes.Count := aGraph.NodeCount;
- for i := 0 to pred(pfiNodes.Count) do
- pfiNodes[i] := AllocMem(sizeof(TitrCounter));
- Reset;
- pfiQueue := TaaPriorityQueueEx.Create(ComparePriority);
- end;
- {--------}
- destructor TaaPriorityFirstIterator.Destroy;
- var
- i : integer;
- begin
- for i := 0 to pred(pfiNodes.Count) do
- pfiDestroyCounter(i);
- pfiNodes.Free;
- pfiQueue.Free;
- inherited Destroy;
- end;
- {--------}
- procedure TaaPriorityFirstIterator.pfiDestroyCounter(aIndex : integer);
- var
- Counter : PitrCounter;
- begin
- Counter := pfiNodes[aIndex];
- if (Counter <> nil) then
- Dispose(Counter);
- end;
- {--------}
- function TaaPriorityFirstIterator.pfiTracePathPrim(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
- var
- Parent : integer;
- begin
- if (aFromIndex = aToIndex) then begin
- {we reached the source node, so print it & return success}
- if Assigned(pfiPrintNode) then
- pfiPrintNode(Self, aToIndex, aExtraData);
- Result := true;
- end
- else begin
- Parent := PitrCounter(pfiNodes[aToIndex])^.cParent;
- if (Parent = -1) then begin
- {we've hit a dead end-there is no path back to the source node}
- Result := false;
- end
- else begin
- {recurse to the parent, if successful print this node}
- if pfiTracePathPrim(aFromIndex, Parent, aExtraData) then begin
- if Assigned(pfiPrintNode) then
- pfiPrintNode(Self, aToIndex, aExtraData);
- Result := true;
- end
- else
- Result := false;
- end;
- end;
- end;
- {--------}
- procedure TaaPriorityFirstIterator.Execute(aEvalPriority : TaaEvalPriority;
- aFromIndex : integer;
- aExtraData : pointer);
- var
- i : integer;
- NewNodeInx : integer;
- Edge : longint;
- OurLevel : integer;
- OurIndex : integer;
- NewPriority: longint;
- begin
- // perform preprocessing on the node
- if Assigned(pfiPreProcess) then
- pfiPreProcess(Self, aFromIndex, aExtraData);
- // mark the node as preprocessed
- with PitrCounter(pfiNodes[aFromIndex])^ do begin
- cMarker := 1;
- cPriority := 0;
- // push the node onto the queue
- cHandle := pfiQueue.Add(pfiNodes[aFromIndex]);
- end;
- // whilst there are still items in the queue...
- while (pfiQueue.Count <> 0) do begin
- // pop the next item off the queue
- OurIndex := PitrCounter(pfiQueue.Remove)^.cIndex;
- // perform postprocessing on the node
- if Assigned(pfiPostProcess) then
- pfiPostProcess(Self, OurIndex, aExtraData);
- // mark the node as postprocessed
- with PitrCounter(pfiNodes[OurIndex])^ do begin
- cMarker := 2;
- OurLevel := cLevel;
- end;
- // iterate through the edges from this node, push unvisited nodes
- // onto the queue
- i := 0;
- while pfiGraph.GetNodeEdge(OurIndex, i, Edge, NewNodeInx) do begin
- with PitrCounter(pfiNodes[NewNodeInx])^ do begin
- if (cMarker = 0) then begin {totally unvisited before}
- // update process information
- cParent := OurIndex;
- cLevel := succ(OurLevel);
- // perform preprocessing on the node
- if Assigned(pfiPreProcess) then
- pfiPreProcess(Self, NewNodeInx, aExtraData);
- // mark the node as preprocessed
- cMarker := 1;
- // calculate the priority
- cPriority := aEvalPriority(Self, OurIndex, Edge, NewNodeInx);
- // push the node onto the queue
- cHandle := pfiQueue.Add(pfiNodes[NewNodeInx]);
- end
- else if (cMarker = 1) then begin {already preprocessed}
- // calculate the new priority
- NewPriority := aEvalPriority(Self, OurIndex, Edge, NewNodeInx);
- // if it is less than the current one, update the node and
- // reheapify the queue
- if (NewPriority < cPriority) then begin
- cParent := OurIndex;
- cLevel := succ(OurLevel);
- cPriority := NewPriority;
- pfiQueue.Replace(cHandle, pfiNodes[NewNodeInx]);
- end;
- end;
- end;
- inc(i);
- end;
- end;
- end;
- {--------}
- procedure TaaPriorityFirstIterator.ExecuteAll(aEvalPriority : TaaEvalPriority;
- aExtraData : pointer);
- var
- i : integer;
- begin
- for i := 0 to pred(pfiGraph.NodeCount) do begin
- if (PitrCounter(pfiNodes[i])^.cMarker = 0) then
- Execute(aEvalPriority, i, aExtraData);
- end;
- end;
- {--------}
- function TaaPriorityFirstIterator.GetPriority(aNodeIndex : integer) : longint;
- begin
- Result := PitrCounter(pfiNodes[aNodeIndex])^.cPriority;
- end;
- {--------}
- procedure TaaPriorityFirstIterator.Reset;
- var
- i : integer;
- begin
- for i := 0 to pred(pfiNodes.Count) do begin
- with PitrCounter(pfiNodes[i])^ do begin
- cIndex := i;
- cMarker := 0;
- cParent := -1;
- cLevel := 0;
- cPriority := InfinitePriority;
- cHandle := nil;
- end;
- end;
- end;
- {--------}
- function TaaPriorityFirstIterator.TracePath(aFromIndex : integer;
- aToIndex : integer;
- aExtraData : pointer) : boolean;
- var
- SavedPreProc : TaaProcessNode;
- SavedPostProc : TaaProcessNode;
- begin
- // we don't want any interruptions
- SavedPreProc := OnPreProcess;
- SavedPostProc := OnPostProcess;
- OnPreProcess := nil;
- OnPostProcess := nil;
- try
- // traverse from the ToIndex node back to the FromIndex node
- // pushing visited nodes on the stack: we'll then unwind the stack
- // to print the shortest path
- Result := pfiTracePathPrim(aFromIndex, aToIndex, aExtraData);
- finally
- OnPreProcess := SavedPreProc;
- OnPostProcess := SavedPostProc;
- end;
- end;
- {====================================================================}
-
-
- {===Interfaced routines==============================================}
- function EvalDijkstrasPriority(aSender : TObject;
- aFromIndex : integer;
- aEdgeCost : longint;
- aToIndex : integer) : longint;
- begin
- with (aSender as TaaPriorityFirstIterator) do
- Result := GetPriority(aFromIndex) + aEdgeCost;
- end;
- {--------}
- function EvalPrimsPriority(aSender : TObject;
- aFromIndex : integer;
- aEdgeCost : longint;
- aToIndex : integer) : longint;
- begin
- Result := aEdgeCost;
- end;
- {--------}
- procedure MinSpanningTree(aGraph : TaaGraph;
- aProcessNode : TaaProcessNode;
- aExtraData : pointer);
- var
- Iter : TaaPriorityFirstIterator;
- begin
- Iter := TaaPriorityFirstIterator.Create(aGraph);
- Iter.OnPostProcess := aProcessNode;
- try
- Iter.Execute(EvalPrimsPriority, 0, aExtraData);
- finally
- Iter.Free;
- end;
- end;
- {--------}
- procedure SmallestCostPath(aGraph : TaaGraph;
- aFromIndex : integer;
- aToIndex : integer;
- aProcessNode : TaaProcessNode;
- aExtraData : pointer);
- var
- Iter : TaaPriorityFirstIterator;
- begin
- Iter := TaaPriorityFirstIterator.Create(aGraph);
- Iter.OnPrintNode := aProcessNode;
- try
- Iter.Execute(EvalDijkstrasPriority, aFromIndex, nil);
- Iter.TracePath(aFromIndex, aToIndex, aExtraData);
- finally
- Iter.Free;
- end;
- end;
-
- {====================================================================}
-
- end.
-